package com.xiaoyu.studyworkspace.service.impl;

import com.xiaoyu.studyworkspace.common.util.PredictionProcessUtil;
import com.xiaoyu.studyworkspace.common.util.UserCode;
import com.xiaoyu.studyworkspace.common.kapaentity.websocket.KapaRoomID;
import com.xiaoyu.studyworkspace.dto.MethodNameDTO;
import com.xiaoyu.studyworkspace.dto.PredictionDTO;
import com.xiaoyu.studyworkspace.dto.RecordDTO;
import com.xiaoyu.studyworkspace.mapper.PredictionMapper;
import com.xiaoyu.studyworkspace.mapper.RecordMapper;
import com.xiaoyu.studyworkspace.mapper.UserMapper;
import com.xiaoyu.studyworkspace.pojo.MethodName;
import com.xiaoyu.studyworkspace.pojo.Prediction;
import com.xiaoyu.studyworkspace.pojo.RecordV3;
import com.xiaoyu.studyworkspace.pojo.UserRelation;
import com.xiaoyu.studyworkspace.service.PredictionService;
import com.xiaoyu.studyworkspace.vo.PredictionVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class PredictionServiceImpl implements PredictionService {


    @Autowired
    private PredictionMapper predictionMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RecordMapper recordMapper;

    @Override
    public PredictionVO getMethodByName(PredictionDTO predictionDTO) {
        String method = predictionDTO.getMethod();
        //去缓存中读取
        PredictionVO predictionVo = (PredictionVO) redisTemplate.opsForValue().get(method);
        //当缓存不存在时候，去数据库读取
        if (predictionVo == null) {
            List<Prediction> predictions = predictionMapper.selectRecordByMethodName(predictionDTO.getMethod());
            double winPercentage = getWinPercentage(predictions);
            PredictionVO predictionVO1 = new PredictionVO();
            predictionVO1.setPredictionList(predictions);
            predictionVO1.setWinPercentage(winPercentage + "%");
            //加入到缓存当中
            redisTemplate.opsForValue().set(method, predictionVO1);
            redisTemplate.expire(method, 10, TimeUnit.MINUTES);
            return predictionVO1;
        }
        return predictionVo;
    }

    /**
     * 每次插入之前把之前的更改了，然后插入一条预测
     *
     * @param recordDTO
     */
    @Override
    @Transactional
    public void insertMethod(RecordDTO recordDTO) {
        //获取名字
        String killRoomName = recordDTO.getRoom_name();
        //取出算法名字
        List<MethodName> methodNameList = predictionMapper.selectMethodNames();
        for (MethodName methodName : methodNameList) {
            LocalDateTime now = LocalDateTime.now();
            //取出对应名字的算法的最后一个???
            Prediction oldPrediction = predictionMapper.selectLastMethods(methodName.getName());
            if (oldPrediction == null) {
                Prediction prediction1 = new Prediction();
                prediction1.setPrediction_room("数据初始化");
                prediction1.setKill_room("数据初始化");
                prediction1.setMethod(methodName.getName());
                prediction1.setGames(0);
                prediction1.setContinue_fail(0);
                prediction1.setWin_count(0);
                prediction1.setCreate_time(LocalDateTime.now());
                predictionMapper.insertNewPrediction(prediction1);
                oldPrediction = prediction1;
            }
            //取出更改
            oldPrediction.setKill_room(killRoomName);
            //
            if (!killRoomName.equals(oldPrediction.getPrediction_room())) {
                //不相同则连胜加一
                oldPrediction.setWin_count(oldPrediction.getWin_count() + 1);
                oldPrediction.setContinue_fail(0);
            } else {
                //预测失败
                oldPrediction.setWin_count(0);
                oldPrediction.setContinue_fail(oldPrediction.getContinue_fail() + 1);
            }
            predictionMapper.updateLastMethod(oldPrediction);

            //插入一条预测
            Prediction newPrediction = new Prediction();
            newPrediction.setMethod(oldPrediction.getMethod());
            Integer games = (Integer) redisTemplate.opsForValue().get("games");
            if (games == null) {
                games = 0;
            }
            newPrediction.setGames(games + 1);
            /**
             * 预测房间的逻辑处理
             */
            processPrediction(newPrediction, killRoomName, methodName);

            newPrediction.setKill_room("???");
            newPrediction.setWin_count(oldPrediction.getWin_count());
            newPrediction.setContinue_fail(oldPrediction.getContinue_fail());
            newPrediction.setCreate_time(now);
            predictionMapper.insertNewPrediction(newPrediction);

            //查出对应算法放去缓存当中，取出100条对应的算法
            List<Prediction> predictionList = predictionMapper.selectRecordByMethodName(methodName.getName());
            double winPercentage = getWinPercentage(predictionList);
            //更新对应的算法胜率
            predictionMapper.UpdateMethodName(methodName.getName(), winPercentage);
            PredictionVO predictionVo = new PredictionVO();
            predictionVo.setPredictionList(predictionList);
            predictionVo.setWinPercentage(winPercentage + "%");
            //加入到缓存当中
            redisTemplate.opsForValue().set(methodName.getName(), predictionVo);
            redisTemplate.expire(methodName.getName(), 10, TimeUnit.MINUTES);
        }
        //寻找三连噶
        Map<String, Integer> statisticsNames = new HashMap<>();
        statisticsNames.put("统计算法三连法", 3);
        statisticsNames.put("统计算法二连法", 2);
        statisticsNames.put("统计算法一连法", 1);
        for (String s : statisticsNames.keySet()) {
            statistics(methodNameList, s, statisticsNames.get(s), statisticsNames);
        }
    }

    private void statistics(List<MethodName> methodNameList, String nameMethod, int index, Map<String, Integer> statisticsNames) {
        Prediction selfPrediction = null;
        MethodName methodName = null;
        for (MethodName name : methodNameList) {
            if (name.getName().equals(nameMethod)) {
                methodName = name;
                selfPrediction = predictionMapper.selectLastMethods(name.getName());
            }
        }
        boolean has = false;
        for (MethodName name : methodNameList) {
            if (statisticsNames.get(name.getName()) == null) {
                //查取其他的算法
                Prediction oldPrediction1 = predictionMapper.selectLastMethods(name.getName());
                if (oldPrediction1.getContinue_fail() == index) {
                    //改成3连算法当中
                    selfPrediction.setPrediction_room(oldPrediction1.getPrediction_room());
                    has = true;
                    if (has) {
                        break;
                    }
                }
            }
        }

        selfPrediction.setPrediction_room(has ? selfPrediction.getPrediction_room() : "本局轮空");
        predictionMapper.updateLastMethodPred(selfPrediction);
        //查出对应算法放去缓存当中，取出100条对应的算法
        List<Prediction> predictionList = predictionMapper.selectRecordByMethodName(methodName.getName());
        double winPercentage = getWinPercentage(predictionList);
        //更新对应的算法胜率
        predictionMapper.UpdateMethodName(methodName.getName(), winPercentage);
        PredictionVO predictionVo = new PredictionVO();
        predictionVo.setPredictionList(predictionList);
        predictionVo.setWinPercentage(winPercentage + "%");
        //加入到缓存当中
        redisTemplate.opsForValue().set(methodName.getName(), predictionVo);
        redisTemplate.expire(methodName.getName(), 10, TimeUnit.MINUTES);
    }

    private void processPrediction(Prediction newPrediction, String killRoomName, MethodName methodName) {
        if (methodName.getName().equals("失一去二法")) {
            newPrediction.setPrediction_room(PredictionProcessUtil.getPredRoomById(methodName.getCode(), killRoomName));
            return;
        }
        if (methodName.getName().equals("统计算法三连法") || methodName.getName().equals("统计算法二连法") || methodName.getName().equals("统计算法一连法")) {
            newPrediction.setPrediction_room("等待中");
            return;
        }
        //插入追龙算法
        if (methodName.getName().equals("追龙预测法")) {
            //找出最大的值，进行预测
            //查询出记录中的最后一条
            RecordV3 recordV3 = recordMapper.selectRecordLastV3();
            ArrayList<Integer> roomCount = new ArrayList<>();
            HashMap<Integer, String> winCountRoom = new HashMap<>();

            winCountRoom.put(recordV3.getYueliang_win(), "月亮湾");
            winCountRoom.put(recordV3.getTingyu_win(), "听雨楼");
            winCountRoom.put(recordV3.getBishui_win(), "碧水间");
            winCountRoom.put(recordV3.getHanyan_win(), "含烟阁");
            winCountRoom.put(recordV3.getQingtian_win(), "晴天阁");

            roomCount.add(recordV3.getBishui_win());
            roomCount.add(recordV3.getHanyan_win());
            roomCount.add(recordV3.getTingyu_win());
            roomCount.add(recordV3.getYueliang_win());
            roomCount.add(recordV3.getQingtian_win());
            Collections.sort(roomCount);
            newPrediction.setPrediction_room(winCountRoom.get(roomCount.get(4)));
            return;
        }

        Random random = new Random();
        int nextInt = random.nextInt(5) + 1;
        newPrediction.setPrediction_room(KapaRoomID.roomName.get(nextInt));
    }

    @Override
    public List<MethodName> getAllMethodNameById(MethodNameDTO methodNameDTO) {
        Integer userId = methodNameDTO.getUser_id();
        List<UserRelation> userRelations = userMapper.selectUserCode(userId);
        if (userRelations == null || userRelations.size() == 0) {
            //如果该用户没有关系表则写入
            UserRelation userRelation = new UserRelation();
            userRelation.setUser_id(userId);
            userRelation.setCode(UserCode.PUBLIC);
            userMapper.insertUserCode(userRelation);
            userRelations.add(userRelation);
        }
        //查询出对应的代码编号
        List<MethodName> methodNameList = predictionMapper.selectMethodNamesByCode(userRelations);
        Collections.sort(methodNameList, new Comparator<MethodName>() {
            @Override
            public int compare(MethodName o1, MethodName o2) {
                return o2.getWin_percentage() - o1.getWin_percentage();
            }
        });
        return methodNameList;
    }

    private static double getWinPercentage(List<Prediction> predictionList) {
        //计算胜率
        double size = predictionList.size();
        double failNumber = 0;
        for (Prediction prediction1 : predictionList) {
            //相同则预测失败
            if (prediction1.getKill_room().equals(prediction1.getPrediction_room())) {
                failNumber += 1;
            }
        }
        return Math.round((size - failNumber) / size * 100);
    }
}
